package org.example.io;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class FileOps {
    public static void anythingCopyByChannel(String from, String to) {
        // need to create file before read and write
        ByteBuffer buffer = ByteBuffer.allocate(8);
        try (SeekableByteChannel rChannel = Files.newByteChannel(Paths.get(from), StandardOpenOption.READ);
             SeekableByteChannel wChannel = Files.newByteChannel(Paths.get(to), StandardOpenOption.WRITE)) {
            while (rChannel.read(buffer) != -1) {
                buffer.flip();
                wChannel.write(buffer);
                buffer.clear();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void textCopyByFiles(String from, String to) {
        try {
            List<String> content = Files.readAllLines(Paths.get(from), StandardCharsets.UTF_8);
            Files.write(Paths.get(to), content, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void binCopyByFiles(String from, String to) {
        try {
            byte[] bytes = Files.readAllBytes(Paths.get(from));
            Files.write(Paths.get(to), bytes, StandardOpenOption.CREATE);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void BinCopyByBuffered(String from, String to) {
        try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(Paths.get(from)));
             BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get(to)))) {
            int length = 0;
            while ((length = bis.read()) != -1) {
                bos.write(length);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public static void textCopyByBuffered(String from, String to) {
        try (BufferedReader br = Files.newBufferedReader(Paths.get(from), StandardCharsets.UTF_8);
             BufferedWriter bw = Files.newBufferedWriter(Paths.get(to), StandardOpenOption.CREATE)) {
            String line = "";
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }
            // The only time you normally need to call flush manually is if you really, really need the data to be on disk now.
            // bw.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static Set<String> walkDir(String dir) throws IOException {
        Path where =
                Optional.ofNullable(dir)
                        .map(Paths::get)
                        .map(Path::normalize)
                        .orElseThrow(() -> new IOException(String.format("unable to locate dir: [%s]", dir)));

        Set<String> files = new HashSet<>();
        String fileName;

        try (DirectoryStream<Path> stream = Files.newDirectoryStream(where)) {
            for (Path path : stream) {
                // 如果是目录跳过
                if (Files.isDirectory(path)) {
                    continue;
                }

                fileName = path.getFileName().toString();
                files.add(fileName);
            }
        } catch (IOException e) {
            System.err.printf("walk dir %s failed, error is [%s]%n", dir, e.getMessage());
            throw e;
        }

        return files;
    }
}
